#include <stdio.h>

#include <openssl/err.h>
#include <openssl/bn.h>

#include "trace.h"

#define ERR_BUF_SIZE            (300u)

/*
 * Returns 1 if a is quadratic residue modulo p, 0 otherwise
 * and -1 for error
 * (Legendre symbol = 1)
 */
int is_quad_res(const char *num, const char  *mod){
    int ret = 0;

    BN_CTX *ctx = BN_CTX_new();

    BIGNUM *one = NULL;
    BIGNUM *two = NULL;
    BIGNUM *L = BN_new();

    char buf[ERR_BUF_SIZE];
    unsigned long errcode;

    BIGNUM *a = NULL;
    BIGNUM *p = NULL;

    BN_dec2bn(&a, num);
    BN_dec2bn(&p, mod);

    /* (a/p) == a^((p-1)/2) (mod p)     */
    /* p is positive, odd, prime !!*/
    BN_dec2bn(&one, "1");
    BN_dec2bn(&two, "2");

    if(!BN_sub(L, p, one)) goto err;

    if(!BN_div(L, NULL, L, two, ctx)) goto err;

    if(!BN_mod_exp(L, a, L, p, ctx)) goto err;

    if(BN_is_one(L)) ret = 1;

    if(traceLevel>=TRACE_LEVEL_DEBUG){
        char *legendre;
        legendre = BN_bn2dec(L);
        if (!legendre) goto err;
        TRACE_DEBUG("Legendre symbol (%s/%s) is: %s\n", num, mod, legendre);
        /* can be +1 or -1 (p-1) */
        OPENSSL_free(legendre);
    }
    goto ok;

    err:
    errcode = ERR_get_error();
    ERR_load_crypto_strings();
    ERR_error_string(errcode, buf);
    TRACE_ERROR("\nquad_res error: %s\n", buf);
    ERR_free_strings();
    ret = -1;

    ok:
    BN_free(one);
    BN_free(two);
    BN_free(L);

    return ret;
}
